home *** CD-ROM | disk | FTP | other *** search
/ PC/CD Gamer UK 120 / CD Gamer Issue 120 (March 2003) (Disc 2).ISO / mods / Q2_Codered / codeRED1_0.exe / Data1.cab / sv_init.c < prev    next >
Encoding:
C/C++ Source or Header  |  2002-08-13  |  11.3 KB  |  466 lines

  1. /*
  2. Copyright (C) 1997-2001 Id Software, Inc.
  3.  
  4. This program is free software; you can redistribute it and/or
  5. modify it under the terms of the GNU General Public License
  6. as published by the Free Software Foundation; either version 2
  7. of the License, or (at your option) any later version.
  8.  
  9. This program is distributed in the hope that it will be useful,
  10. but WITHOUT ANY WARRANTY; without even the implied warranty of
  11. MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  
  12.  
  13. See the GNU General Public License for more details.
  14.  
  15. You should have received a copy of the GNU General Public License
  16. along with this program; if not, write to the Free Software
  17. Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
  18.  
  19. */
  20.  
  21. #include "server.h"
  22.  
  23. server_static_t    svs;                // persistant server info
  24. server_t        sv;                    // local server
  25.  
  26. /*
  27. ================
  28. SV_FindIndex
  29.  
  30. ================
  31. */
  32. int SV_FindIndex (char *name, int start, int max, qboolean create)
  33. {
  34.     int        i;
  35.     
  36.     if (!name || !name[0])
  37.         return 0;
  38.  
  39.     for (i=1 ; i<max && sv.configstrings[start+i][0] ; i++)
  40.         if (!strcmp(sv.configstrings[start+i], name))
  41.             return i;
  42.  
  43.     if (!create)
  44.         return 0;
  45.  
  46.     if (i == max)
  47.         Com_Error (ERR_DROP, "*Index: overflow");
  48.  
  49.     strncpy (sv.configstrings[start+i], name, sizeof(sv.configstrings[i]));
  50.  
  51.     if (sv.state != ss_loading)
  52.     {    // send the update to everyone
  53.         SZ_Clear (&sv.multicast);
  54.         MSG_WriteChar (&sv.multicast, svc_configstring);
  55.         MSG_WriteShort (&sv.multicast, start+i);
  56.         MSG_WriteString (&sv.multicast, name);
  57.         SV_Multicast (vec3_origin, MULTICAST_ALL_R);
  58.     }
  59.  
  60.     return i;
  61. }
  62.  
  63.  
  64. int SV_ModelIndex (char *name)
  65. {
  66.     return SV_FindIndex (name, CS_MODELS, MAX_MODELS, true);
  67. }
  68.  
  69. int SV_SoundIndex (char *name)
  70. {
  71.     return SV_FindIndex (name, CS_SOUNDS, MAX_SOUNDS, true);
  72. }
  73.  
  74. int SV_ImageIndex (char *name)
  75. {
  76.     return SV_FindIndex (name, CS_IMAGES, MAX_IMAGES, true);
  77. }
  78.  
  79.  
  80. /*
  81. ================
  82. SV_CreateBaseline
  83.  
  84. Entity baselines are used to compress the update messages
  85. to the clients -- only the fields that differ from the
  86. baseline will be transmitted
  87. ================
  88. */
  89. void SV_CreateBaseline (void)
  90. {
  91.     edict_t            *svent;
  92.     int                entnum;    
  93.  
  94.     for (entnum = 1; entnum < ge->num_edicts ; entnum++)
  95.     {
  96.         svent = EDICT_NUM(entnum);
  97.         if (!svent->inuse)
  98.             continue;
  99.         if (!svent->s.modelindex && !svent->s.sound && !svent->s.effects)
  100.             continue;
  101.         svent->s.number = entnum;
  102.  
  103.         //
  104.         // take current state as baseline
  105.         //
  106.         VectorCopy (svent->s.origin, svent->s.old_origin);
  107.         sv.baselines[entnum] = svent->s;
  108.     }
  109. }
  110.  
  111.  
  112. /*
  113. =================
  114. SV_CheckForSavegame
  115. =================
  116. */
  117. void SV_CheckForSavegame (void)
  118. {
  119.     char        name[MAX_OSPATH];
  120.     FILE        *f;
  121.     int            i;
  122.  
  123.     if (sv_noreload->value)
  124.         return;
  125.  
  126.     if (Cvar_VariableValue ("deathmatch"))
  127.         return;
  128.  
  129.     Com_sprintf (name, sizeof(name), "%s/save/current/%s.sav", FS_Gamedir(), sv.name);
  130.     f = fopen (name, "rb");
  131.     if (!f)
  132.         return;        // no savegame
  133.  
  134.     fclose (f);
  135.  
  136.     SV_ClearWorld ();
  137.  
  138.     // get configstrings and areaportals
  139.     SV_ReadLevelFile ();
  140.  
  141.     if (!sv.loadgame)
  142.     {    // coming back to a level after being in a different
  143.         // level, so run it for ten seconds
  144.  
  145.         // rlava2 was sending too many lightstyles, and overflowing the
  146.         // reliable data. temporarily changing the server state to loading
  147.         // prevents these from being passed down.
  148.         server_state_t        previousState;        // PGM
  149.  
  150.         previousState = sv.state;                // PGM
  151.         sv.state = ss_loading;                    // PGM
  152.         for (i=0 ; i<100 ; i++)
  153.             ge->RunFrame ();
  154.  
  155.         sv.state = previousState;                // PGM
  156.     }
  157. }
  158.  
  159.  
  160. /*
  161. ================
  162. SV_SpawnServer
  163.  
  164. Change the server to a new map, taking all connected
  165. clients along with it.
  166.  
  167. ================
  168. */
  169. void SV_SpawnServer (char *server, char *spawnpoint, server_state_t serverstate, qboolean attractloop, qboolean loadgame)
  170. {
  171.     int            i;
  172.     unsigned    checksum;
  173.  
  174.     if (attractloop)
  175.         Cvar_Set ("paused", "0");
  176.  
  177.     Com_Printf ("------- Server Initialization -------\n");
  178.  
  179.     Com_DPrintf ("SpawnServer: %s\n",server);
  180.     if (sv.demofile)
  181.         fclose (sv.demofile);
  182.  
  183.     svs.spawncount++;        // any partially connected client will be
  184.                             // restarted
  185.     sv.state = ss_dead;
  186.     Com_SetServerState (sv.state);
  187.  
  188.     // wipe the entire per-level structure
  189.     memset (&sv, 0, sizeof(sv));
  190.     svs.realtime = 0;
  191.     sv.loadgame = loadgame;
  192.     sv.attractloop = attractloop;
  193.  
  194.     // save name for levels that don't set message
  195.     strcpy (sv.configstrings[CS_NAME], server);
  196.     if (Cvar_VariableValue ("deathmatch"))
  197.     {
  198.         sprintf(sv.configstrings[CS_AIRACCEL], "%g", sv_airaccelerate->value);
  199.         pm_airaccelerate = sv_airaccelerate->value;
  200.     }
  201.     else
  202.     {
  203.         strcpy(sv.configstrings[CS_AIRACCEL], "0");
  204.         pm_airaccelerate = 0;
  205.     }
  206.  
  207.     SZ_Init (&sv.multicast, sv.multicast_buf, sizeof(sv.multicast_buf));
  208.  
  209.     strcpy (sv.name, server);
  210.  
  211.     // leave slots at start for clients only
  212.     for (i=0 ; i<maxclients->value ; i++)
  213.     {
  214.         // needs to reconnect
  215.         if (svs.clients[i].state > cs_connected)
  216.             svs.clients[i].state = cs_connected;
  217.         svs.clients[i].lastframe = -1;
  218.     }
  219.  
  220.     sv.time = 1000;
  221.     
  222.     strcpy (sv.name, server);
  223.     strcpy (sv.configstrings[CS_NAME], server);
  224.  
  225.     if (serverstate != ss_game)
  226.     {
  227.         sv.models[1] = CM_LoadMap ("", false, &checksum);    // no real map
  228.     }
  229.     else
  230.     {
  231.         Com_sprintf (sv.configstrings[CS_MODELS+1],sizeof(sv.configstrings[CS_MODELS+1]),
  232.             "maps/%s.bsp", server);
  233.         sv.models[1] = CM_LoadMap (sv.configstrings[CS_MODELS+1], false, &checksum);
  234.     }
  235.     Com_sprintf (sv.configstrings[CS_MAPCHECKSUM],sizeof(sv.configstrings[CS_MAPCHECKSUM]),
  236.         "%i", checksum);
  237.  
  238.     //
  239.     // clear physics interaction links
  240.     //
  241.     SV_ClearWorld ();
  242.     
  243.     for (i=1 ; i< CM_NumInlineModels() ; i++)
  244.     {
  245.         Com_sprintf (sv.configstrings[CS_MODELS+1+i], sizeof(sv.configstrings[CS_MODELS+1+i]),
  246.             "*%i", i);
  247.         sv.models[i+1] = CM_InlineModel (sv.configstrings[CS_MODELS+1+i]);
  248.     }
  249.  
  250.     //
  251.     // spawn the rest of the entities on the map
  252.     //    
  253.  
  254.     // precache and static commands can be issued during
  255.     // map initialization
  256.     sv.state = ss_loading;
  257.     Com_SetServerState (sv.state);
  258.  
  259.     // load and spawn all other entities
  260.     ge->SpawnEntities ( sv.name, CM_EntityString(), spawnpoint );
  261.  
  262.     // run two frames to allow everything to settle
  263.     ge->RunFrame ();
  264.     ge->RunFrame ();
  265.  
  266.     // all precaches are complete
  267.     sv.state = serverstate;
  268.     Com_SetServerState (sv.state);
  269.     
  270.     // create a baseline for more efficient communications
  271.     SV_CreateBaseline ();
  272.  
  273.     // check for a savegame
  274.     SV_CheckForSavegame ();
  275.  
  276.     // set serverinfo variable
  277.     Cvar_FullSet ("mapname", sv.name, CVAR_SERVERINFO | CVAR_NOSET);
  278.  
  279.     Com_Printf ("-------------------------------------\n");
  280. }
  281.  
  282. /*
  283. ==============
  284. SV_InitGame
  285.  
  286. A brand new game has been started
  287. ==============
  288. */
  289. void SV_InitGame (void)
  290. {
  291.     int        i;
  292.     edict_t    *ent;
  293.     char    idmaster[32];
  294.  
  295.     if (svs.initialized)
  296.     {
  297.         // cause any connected clients to reconnect
  298.         SV_Shutdown ("Server restarted\n", true);
  299.     }
  300.     else
  301.     {
  302.         // make sure the client is down
  303.         CL_Drop ();
  304.         SCR_BeginLoadingPlaque ();
  305.     }
  306.  
  307.     // get any latched variable changes (maxclients, etc)
  308.     Cvar_GetLatchedVars ();
  309.  
  310.     svs.initialized = true;
  311.  
  312.     if (Cvar_VariableValue ("coop") && Cvar_VariableValue ("deathmatch"))
  313.     {
  314.         Com_Printf("Deathmatch and Coop both set, disabling Coop\n");
  315.         Cvar_FullSet ("coop", "0",  CVAR_SERVERINFO | CVAR_LATCH);
  316.     }
  317.  
  318.     // dedicated servers are can't be single player and are usually DM
  319.     // so unless they explicity set coop, force it to deathmatch
  320.     if (dedicated->value)
  321.     {
  322.         if (!Cvar_VariableValue ("coop"))
  323.             Cvar_FullSet ("deathmatch", "1",  CVAR_SERVERINFO | CVAR_LATCH);
  324.     }
  325.  
  326.     // init clients
  327.     if (Cvar_VariableValue ("deathmatch"))
  328.     {
  329.         if (maxclients->value <= 1)
  330.             Cvar_FullSet ("maxclients", "8", CVAR_SERVERINFO | CVAR_LATCH);
  331.         else if (maxclients->value > MAX_CLIENTS)
  332.             Cvar_FullSet ("maxclients", va("%i", MAX_CLIENTS), CVAR_SERVERINFO | CVAR_LATCH);
  333.     }
  334.     else if (Cvar_VariableValue ("coop"))
  335.     {
  336.         if (maxclients->value <= 1 || maxclients->value > 4)
  337.             Cvar_FullSet ("maxclients", "4", CVAR_SERVERINFO | CVAR_LATCH);
  338. #ifdef COPYPROTECT
  339.         if (!sv.attractloop && !dedicated->value)
  340.             Sys_CopyProtect ();
  341. #endif
  342.     }
  343.     else    // non-deathmatch, non-coop is one player
  344.     {
  345.         Cvar_FullSet ("maxclients", "1", CVAR_SERVERINFO | CVAR_LATCH);
  346. #ifdef COPYPROTECT
  347.         if (!sv.attractloop)
  348.             Sys_CopyProtect ();
  349. #endif
  350.     }
  351.  
  352.     svs.spawncount = rand();
  353.     svs.clients = Z_Malloc (sizeof(client_t)*maxclients->value);
  354.     svs.num_client_entities = maxclients->value*UPDATE_BACKUP*64;
  355.     svs.client_entities = Z_Malloc (sizeof(entity_state_t)*svs.num_client_entities);
  356.  
  357.     // init network stuff
  358.     NET_Config ( (maxclients->value > 1) );
  359.  
  360.     // heartbeats will always be sent to the id master
  361.     svs.last_heartbeat = -99999;        // send immediately
  362.     Com_sprintf(idmaster, sizeof(idmaster), "192.246.40.37:%i", PORT_MASTER);
  363.     NET_StringToAdr (idmaster, &master_adr[0]);
  364.  
  365.     // init game
  366.     SV_InitGameProgs ();
  367.     for (i=0 ; i<maxclients->value ; i++)
  368.     {
  369.         ent = EDICT_NUM(i+1);
  370.         ent->s.number = i+1;
  371.         svs.clients[i].edict = ent;
  372.         memset (&svs.clients[i].lastcmd, 0, sizeof(svs.clients[i].lastcmd));
  373.     }
  374. }
  375.  
  376.  
  377. /*
  378. ======================
  379. SV_Map
  380.  
  381.   the full syntax is:
  382.  
  383.   map [*]<map>$<startspot>+<nextserver>
  384.  
  385. command from the console or progs.
  386. Map can also be a.cin, .pcx, or .dm2 file
  387. Nextserver is used to allow a cinematic to play, then proceed to
  388. another level:
  389.  
  390.     map tram.cin+jail_e3
  391. ======================
  392. */
  393. void SV_Map (qboolean attractloop, char *levelstring, qboolean loadgame)
  394. {
  395.     char    level[MAX_QPATH];
  396.     char    *ch;
  397.     int        l;
  398.     char    spawnpoint[MAX_QPATH];
  399.  
  400.     sv.loadgame = loadgame;
  401.     sv.attractloop = attractloop;
  402.  
  403.     if (sv.state == ss_dead && !sv.loadgame)
  404.         SV_InitGame ();    // the game is just starting
  405.  
  406.     strcpy (level, levelstring);
  407.  
  408.     // if there is a + in the map, set nextserver to the remainder
  409.     ch = strstr(level, "+");
  410.     if (ch)
  411.     {
  412.         *ch = 0;
  413.             Cvar_Set ("nextserver", va("gamemap \"%s\"", ch+1));
  414.     }
  415.     else
  416.         Cvar_Set ("nextserver", "");
  417.  
  418.     //ZOID special hack for end game screen in coop mode
  419.     if (Cvar_VariableValue ("coop") && !Q_stricmp(level, "victory.pcx"))
  420.         Cvar_Set ("nextserver", "gamemap \"*start\"");
  421.  
  422.     // if there is a $, use the remainder as a spawnpoint
  423.     ch = strstr(level, "$");
  424.     if (ch)
  425.     {
  426.         *ch = 0;
  427.         strcpy (spawnpoint, ch+1);
  428.     }
  429.     else
  430.         spawnpoint[0] = 0;
  431.  
  432.     // skip the end-of-unit flag if necessary
  433.     if (level[0] == '*')
  434.         strcpy (level, level+1);
  435.  
  436.     l = strlen(level);
  437.     if (l > 4 && !strcmp (level+l-4, ".cin") )
  438.     {
  439.         SCR_BeginLoadingPlaque ();            // for local system
  440.         SV_BroadcastCommand ("changing\n");
  441.         SV_SpawnServer (level, spawnpoint, ss_cinematic, attractloop, loadgame);
  442.     }
  443.     else if (l > 4 && !strcmp (level+l-4, ".dm2") )
  444.     {
  445.         SCR_BeginLoadingPlaque ();            // for local system
  446.         SV_BroadcastCommand ("changing\n");
  447.         SV_SpawnServer (level, spawnpoint, ss_demo, attractloop, loadgame);
  448.     }
  449.     else if (l > 4 && !strcmp (level+l-4, ".pcx") )
  450.     {
  451.         SCR_BeginLoadingPlaque ();            // for local system
  452.         SV_BroadcastCommand ("changing\n");
  453.         SV_SpawnServer (level, spawnpoint, ss_pic, attractloop, loadgame);
  454.     }
  455.     else
  456.     {
  457.         SCR_BeginLoadingPlaque ();            // for local system
  458.         SV_BroadcastCommand ("changing\n");
  459.         SV_SendClientMessages ();
  460.         SV_SpawnServer (level, spawnpoint, ss_game, attractloop, loadgame);
  461.         Cbuf_CopyToDefer ();
  462.     }
  463.  
  464.     SV_BroadcastCommand ("reconnect\n");
  465. }
  466.